package com.mojo.concurrent.concurrent_05_util;

import java.util.Map;
import java.util.concurrent.*;

/**
 * CyclicBarrier多线程计算应用
 *
 * @author <a href="mailto:sjj@jianzhimao.com">mojo</a>
 * copyright (C), 2013-2023, 广州九尾信息科技有限公司
 * @date 2023/2/17 14:33
 */
public class CyclicBarrierDemo2 {
     static class BankWaterService implements Runnable {
        /**
         * 创建4个屏障，处理完之后执行当前类的run方法
         */
        private CyclicBarrier c = new CyclicBarrier(4, this);
        /**
         * 假设只有4个sheet，所以只启动4个线程
         */
        private Executor executor = Executors.newFixedThreadPool(4);
        /**
         * 保存每个sheet计算出的银流结果
         */
        private ConcurrentHashMap<String, Integer> sheetBankWaterCount = new ConcurrentHashMap<String, Integer>();

        private void count() {
            for (int i = 0; i < 4; i++) {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                        // 计算当前sheet的银流数据，计算代码省略
                        sheetBankWaterCount.put(Thread.currentThread().getName(), 1);
                        // 银流计算完成，插入一个屏障
                        System.out.println(Thread.currentThread().getName() + "执行完成");
                        try {
                            c.await();
                        } catch (InterruptedException | BrokenBarrierException e) {
                            e.printStackTrace();
                        }
                        c.reset();
                    }
                });

            }
        }

        @Override
        public void run() {
            int result = 0;
            // 汇总每个sheet计算出的结果
            for (Map.Entry<String, Integer> sheet : sheetBankWaterCount.entrySet()) {
                result += sheet.getValue();
            }
            // 将结果输出
            sheetBankWaterCount.put("result", result);
            System.out.println(result);
            // c.reset();
        }

    }

    public static void main(String[] args) {
        BankWaterService bankWaterCount = new BankWaterService();
        bankWaterCount.count();
    }

}
